#ifndef __THREAD_H__
#define __THREAD_H__

#include <string>
#include <thread>
#include <functional>
#include <memory>
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>
#include <atomic>

#include "nocopyable.h"

namespace sylar
{

class Semaphore : public NonCopyable
{
public:
    Semaphore(uint32_t count = 1);
    ~Semaphore();

    void wait();
    void notify();
    
private:
    Semaphore(const Semaphore&) = delete;
    Semaphore(Semaphore&&)  = delete;
    Semaphore& operator=(const Semaphore&) = delete;

private:
    sem_t m_semaphore;

};

template<class T>
struct ScopedLockImpl
{
public:
    ScopedLockImpl(T& mutx)
    : m_mutex(mutx)
    , m_locked(false)
    {
        m_mutex.lock();
        m_locked = true;
    }

    ~ScopedLockImpl()
    {
        unlock();
    }

    void lock()
    {
        if (!m_locked)
        {
            m_locked = true;
            m_mutex.lock();
        }
    }

    void unlock()
    {
        if (m_locked)
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T& m_mutex;
    bool m_locked;
};

template<class T>
struct ReadScopedLockImpl
{
public:
    ReadScopedLockImpl(T& mutx)
    : m_mutex(mutx)
    , m_locked(false)
    {
        m_mutex.rdlock();
        m_locked = true;
    }

    ~ReadScopedLockImpl()
    {
        unlock();
    }

    void lock()
    {
        if (!m_locked)
        {
            m_locked = true;
            m_mutex.rdlock();
        }
    }

    void unlock()
    {
        if (m_locked)
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T& m_mutex;
    bool m_locked;
};

template<class T>
struct WriteScopedLockImpl
{
public:
    WriteScopedLockImpl(T& mutx)
    : m_mutex(mutx)
    , m_locked(false)
    {
        m_locked = true;
        m_mutex.wrlock();
    }

    ~WriteScopedLockImpl()
    {
        unlock();
    }

    void lock()
    {
        if (!m_locked)
        {
            m_locked = true;
            m_mutex.wrlock();
        }
    }

    void unlock()
    {
        if (m_locked)
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T& m_mutex;
    bool m_locked;
};

// 更高性能的锁 可以了解一下
/*********************************************
* 
*
*********************************************/
class Spinlock
{
public:
    using Lock = ScopedLockImpl<Spinlock>;

    Spinlock()
    {
        pthread_spin_init(&m_mutex, 0);
    }

    ~Spinlock()
    {
        pthread_spin_destroy(&m_mutex);
    }

    void lock()
    {
        pthread_spin_lock(&m_mutex);
    }

    void unlock()
    {
        pthread_spin_unlock(&m_mutex);
    }
    
private:
    pthread_spinlock_t m_mutex;
};

// 验证不加锁
class  NullMutex
{
public:
    using Lock = ScopedLockImpl<NullMutex>;
    NullMutex()
    {
    }

    ~NullMutex()
    {
    }

    void lock()
    {
    }

    void unlock()
    {
    }

private:

};

class  NullRWMutex
{
public:
    using ReadLock = ReadScopedLockImpl<NullRWMutex>;
    using WriteLock = WriteScopedLockImpl<NullRWMutex>;

    NullRWMutex()
    {
    }

    ~NullRWMutex()
    {
    }

   void rdlock()
    {
    }

    void wrlock()
    {
    }

    void unlock()
    {
    }

private:

};

class Mutex
{
public:
    using Lock = ScopedLockImpl<Mutex>;

public:
    Mutex()
    {
        pthread_mutex_init(&m_mutex, nullptr);
    }

    ~Mutex()
    {
        pthread_mutex_destroy(&m_mutex);
    }

    void lock()
    {
        pthread_mutex_lock(&m_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&m_mutex);
    }
private:
    pthread_mutex_t m_mutex;
};

class RWMutex
{
public:
    using ReadLock = ReadScopedLockImpl<RWMutex>;
    using WriteLock = WriteScopedLockImpl<RWMutex>;

public:
    RWMutex()
    {
        pthread_rwlock_init(&m_rwlock, NULL);
    }

    ~RWMutex()
    {
        pthread_rwlock_destroy(&m_rwlock);
    }

    void rdlock()
    {
        pthread_rwlock_rdlock(&m_rwlock);
    }

    void wrlock()
    {
        pthread_rwlock_wrlock(&m_rwlock);
    }

    void unlock()
    {
        pthread_rwlock_unlock(&m_rwlock);
    }

private:
    pthread_rwlock_t m_rwlock;
};

class CASLock
{
public:
    CASLock()
    {
        m_mutex.clear();
    }

    ~CASLock()
    {

    }

    void lock()
    {
        while(std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
    }

    void unlock()
    {
        std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
    }

private:
    volatile std::atomic_flag m_mutex;
};

class Thread
{
public:
    using Ptr = std::shared_ptr<Thread>;

    Thread(std::function<void()> cb, const std::string& name);
    ~Thread();

    void join();
    static Thread* GetThis();
    static void SetName(const std::string& name);
    static const std::string& GetName();

    pid_t getId() const { return m_id; }
    std::string getName() { return m_name; };

private:
    Thread(const Thread&) = delete;
    Thread(Thread&&) = delete;

    Thread& operator=(const Thread&) = delete;

    static void* run(void* arg);

private:
    pid_t m_id = -1;
    pthread_t m_thread = 0;
    std::function<void()> m_cb;
    std::string m_name;

    Semaphore m_semaphore;
};



}




#endif